// Año: 2011
// Autor: Eduardo Sanchez

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FILENAME "base.txt"

// Declaracion de estructuras
typedef struct s_fecha{
    int dia;
    int mes;
    int anio;
} t_fecha;


typedef struct s_campo{
    short id;
    char nombre[50];
    t_fecha fecha;
    long cuenta;
} t_campo;


//Fin declaracion de estructuras

typedef struct s_bdd{
    t_campo c;
    struct s_bdd* next;
} t_bdd;


typedef struct s_lista {
		t_bdd *inicio;
		int tam;
} t_lista;



t_lista inicializar(t_campo dato_nuevo){    
    t_lista lista;
    t_bdd *entrada;
    entrada = (t_bdd *) malloc(sizeof(t_bdd));
    entrada->c = dato_nuevo;
    entrada->next = NULL;
    lista.inicio = entrada;
    lista.tam=1;
    return (lista);
}


t_lista agregar(t_lista lista, t_campo dato_nuevo){    
    t_bdd *entrada;
    entrada = (t_bdd *) malloc(sizeof(t_bdd));
    entrada->c = dato_nuevo;
    entrada->next = lista.inicio;
    lista.inicio = entrada;
    lista.tam++;
    return (lista);
}


int liberar(t_lista *lista){    
    t_bdd *entrada=lista->inicio;
    while (entrada!=NULL){
        lista->inicio=entrada->next;
        free(entrada);
        entrada = lista->inicio;
        lista->tam--;
    }
    return (0);
}

// PRECOND: lista tiene al menos un elemento!!
int mostrar_lista(t_lista lista){
    t_bdd *entrada = lista.inicio;
    do {
        mostrar_campo(entrada->c);
        entrada = entrada->next;
    } while (entrada!=NULL);
    return 0;
}

t_fecha retornar_fecha(int dia, int mes, int anio){
    t_fecha f;
    f.dia = dia;
    f.mes = mes;
    f.anio = anio;
    return (f);
}

// Declaracion de funciones auxiliares..
int mostrar_fecha(t_fecha f){
    printf("Fecha: %d/%d/%d",f.dia, f.mes, f.anio);
    return 0;
}

int mostrar_campo(t_campo c){
    printf("id: %d\t Nombre: %s\t\t\t", c.id, c.nombre);
    mostrar_fecha(c.fecha);
    printf("\tCuenta: %lx\n", c.cuenta);
    return 0;
}

int insertar_campo(t_campo *c, short id_nuevo, char nombre_nuevo[50], t_fecha fecha_nueva, unsigned long cuenta_nueva){
    c->id=id_nuevo;
    strcpy(c->nombre, nombre_nuevo);
    c->fecha=fecha_nueva;
    c->cuenta=cuenta_nueva;
    return 0;
}


//bajar_a_archivo



int bajar_estructura_binaria_a_archivo(t_lista lista){
    FILE *p = NULL;
    char *file = FILENAME;
    t_bdd *ptr_campo;

    p = fopen(file, "w+");
    if (p== NULL) {
        printf("Error in opening a file..%s\n", file);
    }

    ptr_campo = lista.inicio;

    while (ptr_campo!=NULL){
        fwrite(&(ptr_campo->c), sizeof(t_campo), 1, p);
        ptr_campo = ptr_campo->next;
    }

    fclose(p);
    return 0;
}


int bajar_cadena_caracteres_a_archivo(t_lista lista){
    FILE *p = NULL;
    char *file = FILENAME;
    t_bdd *ptr_campo;
    char buffer[1024];

    p = fopen(file, "w+");
    if (p== NULL) {
        printf("Error in opening a file..%s\n", file);
    }

    ptr_campo = lista.inicio;
    memset(buffer, 0, sizeof(buffer)); // inicializo todo el buffer a 0;
    while (ptr_campo!=NULL){
        sprintf(buffer, "%hd %s %d %d %d %lx\r\n", (ptr_campo->c).id, (ptr_campo->c).nombre, (ptr_campo->c).fecha.dia, (ptr_campo->c).fecha.mes, (ptr_campo->c).fecha.anio, (ptr_campo->c).cuenta);
        fwrite(buffer, strlen(buffer), 1, p);
        ptr_campo = ptr_campo->next;
    }

    fclose(p);
    return 0;
}


// La siguiente funcion asume que al menos existe un campo completo de tipo t_campo en el archivo
t_lista levantar_estructura_binaria_de_archivo(){
    FILE *p = NULL;
    char *file = FILENAME;
    int campos=0;
    t_lista lista;
    t_campo dato_nuevo;

    p = fopen(file, "r");
    if (p== NULL) {
        printf("Error in opening a file..%s\n", file);
        lista.inicio=NULL;
        return lista;
    }

    fread(&dato_nuevo, sizeof(t_campo), 1, p);
    lista = inicializar(dato_nuevo);
    campos++;

    while (fread(&dato_nuevo, sizeof(t_campo), 1, p)!=0){
        lista = agregar(lista, dato_nuevo);
        campos++;
    }

    fclose(p);
    printf("Se ingresaron %d campos en memoria!\n", campos);
    return (lista);
}

// precondicion de esta funcion: tener al menos un 
t_lista levantar_cadena_caracteres_de_archivo(){
    FILE *p = NULL;
    char *file = FILENAME;
    int campos=0;
    t_lista lista;
    t_campo dato_nuevo;
    t_fecha fecha;
    char buffer[1024];

    p = fopen(file, "r");
    if (p== NULL) {
        printf("Error in opening a file..%s\n", file);
        lista.inicio=NULL;
        return lista;
    }



    fgets (buffer , 1024 , p); // primera lectura

    //  printf("%s",buffer); //raw buffer con todos los campos separados por espacio
    sscanf(buffer, "%hd %s %d %d %d %lx\r\n", &dato_nuevo.id, dato_nuevo.nombre, &fecha.dia, &fecha.mes, &fecha.anio, &dato_nuevo.cuenta);
    dato_nuevo.fecha = retornar_fecha(fecha.dia, fecha.mes, fecha.anio);
    lista = inicializar(dato_nuevo);
    campos++;


    while (fgets (buffer , 1024 , p)!=0){
        sscanf(buffer, "%hd %s %d %d %d %lx\r\n", &dato_nuevo.id, dato_nuevo.nombre, &fecha.dia, &fecha.mes, &fecha.anio, &dato_nuevo.cuenta);
        dato_nuevo.fecha = retornar_fecha(fecha.dia, fecha.mes, fecha.anio);
        lista = agregar(lista, dato_nuevo);
        campos++;
    }

    fclose(p);
    printf("Se ingresaron %d campos en memoria!\n", campos);
    return (lista);
}


//Funcion principal
int main(int argc, char **argv){
    t_campo c;
    t_lista lista;
    lista.inicio=NULL;

    if (argc<2) {
        printf("No se ingreso ningún argumento!\n");
        printf("Argumentos:\n");
        printf("\t'crear_binario': crea un archivo de test con algunos campos binarios de tipo t_campo\n");
        printf("\t'mostrar_binario': levantará el contenido binario del archivo de test y se lo mostrará por pantalla\n");
    } else
    {
        if (strcmp(argv[1], "crear_binario")==0){
            printf("Se creará un archivo de test con algunos campos de tipo_t_campo!\n");
            insertar_campo(&c, 5000, "AliBaba", retornar_fecha(21,3,1000), 0xAABBCCEEFF001122);
            lista = inicializar(c);
            insertar_campo(&c, 5050, "Aristoteles", retornar_fecha(21,3,1870), 0xaa55bb66);
            lista = agregar(lista, c);
            insertar_campo(&c, 1000, "Aristofalo", retornar_fecha(16,12,2000), 0x123456789ABCD);
            lista = agregar(lista, c);
            bajar_estructura_binaria_a_archivo(lista);
            liberar(&lista);
            printf("Done!\n");
        } else if (strcmp(argv[1], "mostrar_binario")==0){
            printf("Se levantará el contenido binario del archivo de test y se lo mostrará por pantalla!\n");
            lista = levantar_estructura_binaria_de_archivo();
            if (lista.inicio!=NULL){ // esto es porque mostrar lista espera al menos un elemento
                mostrar_lista(lista);
            }   
            liberar(&lista);
            printf("Done!\n");
        } else if (strcmp(argv[1], "crear_cadena")==0){
            printf("Se Creará un archivo de test con algunos campos en formato cadena de caracteres!\n");
            insertar_campo(&c, 5000, "AliBaba", retornar_fecha(21,3,1000), 0xAABBCCEEFF001122);
            lista = inicializar(c);
            insertar_campo(&c, 5050, "Aristoteles", retornar_fecha(21,3,1870), 0xaa55bb66);
            lista = agregar(lista, c);
            insertar_campo(&c, 1000, "Aristofalo", retornar_fecha(16,12,2000), 0x123456789ABCD);
            lista = agregar(lista, c);
            bajar_cadena_caracteres_a_archivo(lista);
            liberar(&lista);
            printf("Done!\n");

        } else if (strcmp(argv[1], "mostrar_cadena")==0){
            printf("Se levantará el contenido de la cadena de caracteres en el archivo de test y se lo mostrará por pantalla!\n");
            lista = levantar_cadena_caracteres_de_archivo();
            if (lista.inicio!=NULL){ // esto es porque mostrar lista espera al menos un elemento
                mostrar_lista(lista);
            }   
            liberar(&lista);
            printf("Done!\n");


        } else {
            printf("No se ingresó ninguna opción valida!\n");
        }
    
    }

    return 0;
}

/*


int main2(int argc, char argv[]){
    t_fecha fecha;

    t_lista lista;
    short id=5000;
    char nombre[50]="Ali Baba y los 40";
    unsigned long cuenta=0xAABBCCEEFF001122;
    fecha.dia=24;
    fecha.mes=3;
    fecha.anio=1981;

    insertar_campo(&c, id, nombre, fecha, cuenta);
    lista = inicializar(c);
    insertar_campo(&c, 5050, "Aristoteles Gomez", fecha, 0xaa55bb66);
    lista = agregar(lista, c);

    insertar_campo(&c, 1000, "Aristofalo del Valle", retornar_fecha(16,12,2000), 0x123456789ABCD);
    lista = agregar(lista, c);

//    mostrar_lista(lista);

    bajar_estructura_binaria_a_archivo(lista);
// Liberar la memoria dinamica..
    liberar(&lista);
    printf("\n\n\n");
return 0;
}*/
